//Erstellt von Moritz Liepe
package main.simulation;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import main.IModuleControl;
import main.IOControl;
import main.Module;
import main.ModuleEditor;
import main.editor.VOSEditor;

import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.services.ISourceProviderService;


public class SimulationController extends Thread
{
	private Map<VOSEditor,Boolean> editorList = new HashMap<VOSEditor, Boolean>();
	private VOSEditor currentVOSEditor = null;
	
	private Object monitor = new Object();
	private boolean runSimulation = true;
	
	public void setFocus(VOSEditor editor)
	{
		synchronized(this.monitor)
		{
			this.currentVOSEditor = editor;
			Boolean currentState = editorList.get(editor);
			if(currentState == null)
			{
				currentState = false;
				editorList.put(editor, currentState);
			}
			setRunStatus(currentState);
		}
		
	}
	
	public void dispose(VOSEditor editor)
	{
		synchronized(this.monitor)
		{
			this.editorList.remove(editor);
			if((this.currentVOSEditor != null) && (this.currentVOSEditor == editor))
			{
				this.currentVOSEditor = null;
			}
		}
	}
	
	public void playEditor(VOSEditor editor)
	{
		synchronized(this.monitor)
		{
			Boolean currentState = editorList.get(editor);
			if(currentState == null) 
			{
				return;
			}
			if(! currentState.booleanValue())
			{
				editorList.put(editor,true);
				setRunStatus(true);
			}
		}
	}
	
	public void stopEditor(VOSEditor editor)
	{
		synchronized(this.monitor)
		{
			Boolean currentState = editorList.get(editor);
			if(currentState == null) 
			{
				return;
			}
			if(currentState.booleanValue())
			{
				editorList.put(editor,false);
				setRunStatus(false);
			}
		}
	}
	
	public static void setRunStatus(boolean run)
	{
		ISourceProviderService service = (ISourceProviderService)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(ISourceProviderService.class);
		RunStateProvider sessionSourceProvider = (RunStateProvider)service.getSourceProvider(RunStateProvider.RUN_STATE);
		sessionSourceProvider.setCurrentRunState(run ? RunStateProvider.STATE_PLAY : RunStateProvider.STATE_STOP); 
	}

	@Override
	public void run() 
	{
		Map<String, IBehavior> simulationMap = new HashMap<String, IBehavior>();
		
		simulationMap.put("COUNTER", new CounterBehavior());
		simulationMap.put("SUMMAND", new SummandBehavior());
		simulationMap.put("SUM", new SumBehavior());
		simulationMap.put("FULLADDER", new FullAdderBehavior());
		
		while(runSimulation)
		{
			try
			{
				for(Entry<VOSEditor,Boolean> editorEntry : editorList.entrySet())
				{
					if(editorEntry.getValue().booleanValue())
					{
						try
						{
							VOSEditor vosEditor = editorEntry.getKey();
							ModuleEditor moduleEditor = vosEditor.getModuleEditor();
							
							//Process Modules
							
							for(int i = 0; i < moduleEditor.getChildren().size(); i++)
							{
								Figure child = (Figure)moduleEditor.getChildren().get(i);
								if(child instanceof Module)
								{
									Module module = (Module)child;
									
									IBehavior behavior = simulationMap.get(module.getSIMID());
									if(behavior != null)
									{
										try
										{
											behavior.simulate(module);
										}
										catch(Exception e)
										{
											e.printStackTrace();
										}
									}
								}
							}
							
							//Process Connections
							
							for(int i = 0; i < moduleEditor.getChildren().size(); i++)
							{
								Figure child = (Figure)moduleEditor.getChildren().get(i);
								if(child instanceof PolylineConnection)
								{
									PolylineConnection currentConnection = (PolylineConnection)child;
									IOControl sourceControl = ((IOControl)currentConnection.getSourceAnchor().getOwner());
									IOControl targetControl = ((IOControl)currentConnection.getTargetAnchor().getOwner());
									
									String sourceValue = sourceControl.getValue();
									if((sourceControl.getType() != null) && (sourceControl.getType().equalsIgnoreCase(IModuleControl.TYPE_OUTPUT)) && (sourceValue != null))
									{
										String targetValue = targetControl.getValue();
										if(! sourceControl.equals(targetValue))
										{
											Display.getDefault().asyncExec(new SetControlValue(targetControl,sourceValue));
										}
									}
								}
							}
						}
						catch(Exception e)
						{
							e.printStackTrace();
						}
					}
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			
			try
			{
				Thread.sleep(500);
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	public void setRunSimulation(boolean runSimulation) 
	{
		this.runSimulation = runSimulation;
	}
	
	
}
